#include "Thread.hpp"
#include <vector>
#include <mutex>

using namespace ThreadModule;
using std::vector;


int ticket = 1000;
std::mutex mtx;


int subOnce(vector<int>& th_v, int thread_num)
{
    while(true)
    {
        std::lock_guard<std::mutex> lock(mtx);
        if(ticket > 0)
        {
            std::cout << "thread-" << thread_num << " -> now resitual ticket = " << ticket << std::endl;
            --ticket;
            std::cout << thread_num << " ******** th_v ++ ******** " << th_v.at(thread_num - 1)++ << std::endl;
            usleep(1000);
        }
        else{
            break;
        }
    }
    std::cout << "&&&&&&&&&&&&& in thread_v address = " << &th_v[0] << std::endl;
    return ticket;
}

// void test1()
// {
//     using ThreadDataType = ThreadData<int(vector<int>&, int), vector<int>&, int>;
//     vector<ThreadDataType*> v;
//     vector<int> thread_ticket_v(4, 0);

//     v.emplace_back(new ThreadDataType("thread-1", subOnce, ref(thread_ticket_v), 1));
//     v.emplace_back(new ThreadDataType("thread-2", subOnce, ref(thread_ticket_v), 2));
//     v.emplace_back(new ThreadDataType("thread-3", subOnce, ref(thread_ticket_v), 3));
//     v.emplace_back(new ThreadDataType("thread-4", subOnce, ref(thread_ticket_v), 4));

//     for(auto& e : v)
//     {
//         int result = *(int*)(e->getThreadPtr()->Join());
//         usleep(1000);
//         std::cout << e->getName() << "=>Join Result = " << result << std::endl;
//         delete e;
//     }

//     std::cout << "last ticket = " << ticket << std::endl;

//     for(int i = 0; i < thread_ticket_v.size(); i++)
//     {
//         std::cout << "thread-" << i+1 << " got tickets = " << thread_ticket_v.at(i) << std::endl;
//     }
//     std::cout << "&&&&&&&&&&&&& out thread_v address = " << &thread_ticket_v[0] << std::endl;
// }

void test2()
{
    using ThreadType = Thread<int(vector<int>&, int), vector<int>&, int>;
    vector<ThreadType*> v;
    vector<int> thread_ticket_v(4, 0);

    v.emplace_back(new ThreadType(subOnce, ref(thread_ticket_v), 1));
    v.emplace_back(new ThreadType(subOnce, ref(thread_ticket_v), 2));
    v.emplace_back(new ThreadType(subOnce, ref(thread_ticket_v), 3));
    v.emplace_back(new ThreadType(subOnce, ref(thread_ticket_v), 4));

    for(auto& e : v)
    {
        int result = *(int*)(e->Join());
        usleep(1000);
        std::cout << "Join Result = " << result << std::endl;
        delete e;
    }

    std::cout << "last ticket = " << ticket << std::endl;

    for(int i = 0; i < thread_ticket_v.size(); i++)
    {
        std::cout << "thread-" << i+1 << " got tickets = " << thread_ticket_v.at(i) << std::endl;
    }
    std::cout << "&&&&&&&&&&&&& out thread_v address = " << &thread_ticket_v[0] << std::endl;
}


// int subOnce(vector<int>* th_v, int thread_num)
// {
//     while(true)
//     {
//         std::lock_guard<std::mutex> lock(mtx);
//         if(ticket > 0)
//         {
//             std::cout << "thread-" << thread_num << " -> now resitual ticket = " << ticket << std::endl;
//             --ticket;
//             std::cout << thread_num << " ******** th_v ++ ******** " << th_v->at(thread_num - 1)++ << std::endl;
//             usleep(1000);
//         }
//         else{
//             break;
//         }
//     }
//     return ticket;
// }


// void test1()
// {
//     using ThreadDataType = ThreadData<int(vector<int>*, int), vector<int>*, int>;
//     vector<ThreadDataType*> v;
//     vector<int> thread_ticket_v(4, 0);

//     v.emplace_back(new ThreadDataType("thread-1", subOnce, &thread_ticket_v, 1));
//     v.emplace_back(new ThreadDataType("thread-2", subOnce, &thread_ticket_v, 2));
//     v.emplace_back(new ThreadDataType("thread-3", subOnce, &thread_ticket_v, 3));
//     v.emplace_back(new ThreadDataType("thread-4", subOnce, &thread_ticket_v, 4));

//     for(auto& e : v)
//     {
//         int result = *(int*)(e->getThreadPtr()->Join());
//         usleep(1000);
//         std::cout << e->getName() << "=>Join Result = " << result << std::endl;
//         delete e;
//     }

//     std::cout << "last ticket = " << ticket << std::endl;

//     for(int i = 0; i < thread_ticket_v.size(); i++)
//     {
//         std::cout << "thread-" << i+1 << " got tickets = " << thread_ticket_v.at(i) << std::endl;
//     }
// }

int main()
{
    //test1();
    test2();

    return 0;
}